// 12.4.2 包扩展的时机
// 包扩展（Pack Expansion）是变参模板中的核心机制，理解它何时以及如何发生对于正确使用变参模板至关重要。本节讨论包扩展的各种时机和上下文。

// 直接上下文中的包扩展
// 包扩展最常见的情况是在直接上下文中展开参数包：
template <typename... Types>
void printTypes()
{
    // 直接上下文中的包扩展
    using List = std::tuple<Types...>;
}
// 这种扩展是最直观的，参数包中的每个元素都会被替换到模式中。

// 函数调用中的包扩展
// 函数调用是包扩展的常见场景：
template <typename... Args>
void forward(Args &&...args)
{
    // 函数调用中的包扩展
    someFunction(std::forward<Args>(args)...);
}
// 在这种情况下，包扩展会生成一系列函数参数。

// 初始化上下文中的包扩展
// 包扩展可以用于各种初始化上下文：
// 数组初始化
template <typename... Args>
void arrayInit(Args... args)
{
    int values[] = {args...};
}

// 类成员初始化
template <typename... Args>
struct Tuple
{
    std::tuple<Args...> data;
};

// 构造函数初始化列表
template <typename... Args>
class Container
{
    std::tuple<Args...> elements;

public:
    Container(Args... args) : elements(args...) {}
};

// 基类和成员初始化器中的包扩展
// 包扩展可以用于基类列表和成员初始化器：
// 基类列表中的包扩展
template <typename... Bases>
class Derived : public Bases...
{
public:
    // 构造函数中的包扩展
    using Bases::Bases...; // 继承所有基类的构造函数
};

// 委托构造函数中的包扩展
template <typename... Args>
class Widget
{
public:
    Widget(int i, Args... args) : Widget(args..., i) {}
    Widget(Args... args, int i) { /*...*/ }
};

// 模板参数列表中的包扩展
// 包扩展可以出现在模板参数列表中：
// 模板参数列表中的包扩展
template <typename... Types>
class Tuple
{
};

template <typename... Types>
using AliasTuple = Tuple<Types...>;

// 嵌套模板中的包扩展
template <typename... Types>
class Nested
{
    Tuple<std::pair<Types, Types>...> pairs;
};

// 多重包扩展
// 当一个表达式中有多个参数包时，它们会同步展开：
// 多重包扩展
template <typename... Types, typename... Args>
void multiExpand(Types... types, Args... args)
{
    // 同步展开两个参数包
    std::tuple<Types...> t(args...); // 要求sizeof...(Types) == sizeof...(Args)
}

// 复杂模式中的多重包扩展
template <typename... Types>
void complexExpand(Types... args)
{
    // 在一个复杂表达式中展开参数包
    std::tuple<std::pair<Types, Types>...> pairs;
}